package com.gitee.wsl.common.ui.ext.shape


import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.CutCornerShape
import androidx.compose.foundation.shape.GenericShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Immutable
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.graphics.Matrix
import androidx.compose.ui.graphics.Path
import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.unit.LayoutDirection
import kotlin.math.PI
import kotlin.math.cos
import kotlin.math.sin


/**
 * Common ancestor for list of shapes, paths or images to crop inside [CropOutlineContainer]
 */
interface CropOutline {
    val id: Int
    val title: String
}

/**
 * Crop outline that contains a [Shape] like [RectangleShape] to draw frame for cropping
 */
interface CropShape : CropOutline {
    val shape: Shape
}

/**
 * Crop outline that contains a [Path] to draw frame for cropping
 */
interface CropPath : CropOutline {
    val path: Path
}

/**
 * Crop outline that contains a [ImageBitmap]  to draw frame for cropping. And blend modes
 * to draw
 */
interface CropImageMask : CropOutline {
    val image: ImageBitmap
}

/**
 * Wrapper class that implements [CropOutline] and is a shape
 * wrapper that contains [RectangleShape]
 */
@Immutable
data class RectCropShape(
    override val id: Int,
    override val title: String,
) : CropShape {
    override val shape: Shape = RectangleShape
}

/**
 * Wrapper class that implements [CropOutline] and is a shape
 * wrapper that contains [RoundedCornerShape]
 */
@Immutable
data class RoundedCornerCropShape(
    override val id: Int,
    override val title: String,
    val cornerRadius: CornerRadiusProperties = CornerRadiusProperties(),
    override val shape: RoundedCornerShape = RoundedCornerShape(
        topStartPercent = cornerRadius.topStartPercent,
        topEndPercent = cornerRadius.topEndPercent,
        bottomEndPercent = cornerRadius.bottomEndPercent,
        bottomStartPercent = cornerRadius.bottomStartPercent
    )
) : CropShape

/**
 * Wrapper class that implements [CropOutline] and is a shape
 * wrapper that contains [CutCornerShape]
 */
@Immutable
data class CutCornerCropShape(
    override val id: Int,
    override val title: String,
    val cornerRadius: CornerRadiusProperties = CornerRadiusProperties(),
    override val shape: CutCornerShape = CutCornerShape(
        topStartPercent = cornerRadius.topStartPercent,
        topEndPercent = cornerRadius.topEndPercent,
        bottomEndPercent = cornerRadius.bottomEndPercent,
        bottomStartPercent = cornerRadius.bottomStartPercent
    )
) : CropShape

/**
 * Wrapper class that implements [CropOutline] and is a shape
 * wrapper that contains [CircleShape]
 */
@Immutable
data class OvalCropShape(
    override val id: Int,
    override val title: String,
    val ovalProperties: OvalProperties = OvalProperties(),
    override val shape: Shape = CircleShape
) : CropShape


/**
 * Wrapper class that implements [CropOutline] and is a shape
 * wrapper that contains [CircleShape]
 */
@Immutable
data class PolygonCropShape(
    override val id: Int,
    override val title: String,
    val polygonProperties: PolygonProperties = PolygonProperties(),
    override val shape: Shape = Shapes.createPolygonShape(polygonProperties.sides, polygonProperties.angle)
) : CropShape

/**
 * Wrapper class that implements [CropOutline] and is a [Path] wrapper to crop using drawable
 * files converted fom svg or Vector Drawable to [Path]
 */
@Immutable
data class CustomPathOutline(
    override val id: Int,
    override val title: String,
    override val path: Path
) : CropPath

/**
 * Wrapper class that implements [CropOutline] and is a [ImageBitmap] wrapper to crop
 * using a reference png and blend modes to crop
 */
@Immutable
data class ImageMaskOutline(
    override val id: Int,
    override val title: String,
    override val image: ImageBitmap,
) : CropImageMask

@Immutable
data class CornerRadiusProperties(
    val topStartPercent: Int = 20,
    val topEndPercent: Int = 20,
    val bottomStartPercent: Int = 20,
    val bottomEndPercent: Int = 20
)

@Immutable
data class PolygonProperties(
    val sides: Int = 6,
    val angle: Float = 0f,
    val offset: Offset = Offset.Zero
)

@Immutable
data class OvalProperties(
    val startAngle: Float = 0f,
    val sweepAngle: Float = 360f,
    val offset: Offset = Offset.Zero
)


/**
 * Creates a polygon with number of [sides] centered at ([cx],[cy]) with [radius].
 * ```
 *  To generate regular polygons (i.e. where each interior angle is the same),
 *  polar coordinates are extremely useful. You can calculate the angle necessary
 *  to produce the desired number of sides (as the interior angles total 360º)
 *  and then use multiples of this angle with the same radius to describe each point.
 * val x = radius * Math.cos(angle);
 * val y = radius * Math.sin(angle);
 *
 * For instance to draw triangle loop thrice with angle
 * 0, 120, 240 degrees in radians and draw lines from each coordinate.
 * ```
 */
fun Path.Companion.createPolygonPath(cx: Float, cy: Float, sides: Int, radius: Float): Path {

    val angle = 2.0 * PI / sides

    return Path().apply {
        moveTo(
            cx + (radius * cos(0.0)).toFloat(),
            cy + (radius * sin(0.0)).toFloat()
        )
        for (i in 1 until sides) {
            lineTo(
                cx + (radius * cos(angle * i)).toFloat(),
                cy + (radius * sin(angle * i)).toFloat()
            )
        }
        close()
    }
}


/**
 * Create a polygon shape
 */
fun Shapes.createPolygonShape(sides: Int, degrees: Float = 0f): GenericShape {
    return GenericShape { size: Size, _: LayoutDirection ->

        val radius = size.width.coerceAtMost(size.height) / 2
        addPath(
            Path.createPolygonPath(
                cx = size.width / 2,
                cy = size.height / 2,
                sides = sides,
                radius = radius
            )
        )
        val matrix = Matrix()
        /*matrix.postRotate(degrees, size.width / 2, size.height / 2)
        this.asAndroidPath().transform(matrix)*/
        matrix.rotateX(degrees)
        matrix.translate(size.width / 2, size.height / 2)
        this.transform(matrix)
    }
}

/**
 * Value class for containing aspect ratio
 * and [AspectRatio.Original] for comparing
 */
@Immutable
data class AspectRatio(val value: Float) {
    companion object {
        val Original = AspectRatio(-1f)
    }
}

/**
 * Creates a [Rect] shape with given aspect ratio.
 */
fun Shapes.createRectShape(aspectRatio: AspectRatio = AspectRatio.Original): GenericShape {
    return GenericShape { size: Size, _: LayoutDirection ->
        val value = aspectRatio.value

        val width = size.width
        val height = size.height
        val shapeSize =
            if (aspectRatio == AspectRatio.Original) Size(width, height)
            else if (value > 1) Size(width = width, height = width / value)
            else Size(width = height * value, height = height)

        addRect(Rect(offset = Offset.Zero, size = shapeSize))
    }
}